﻿// main.cpp
#include "rtweekend.h"

#include "camera.h"
#include "color.h"
#include "hittable_list.h"
#include "material.h"
#include "sphere.h"

#include <iostream>
#include <fstream>
#include <chrono>

/*
    快速熟悉：
    ray_color() -> wold.hit() -> sphere.hit() -> material.scatter()

    ray_color()：返回光线与物体交点的颜色，超过递归深度就返回0，否则递归计算散射光颜色，散射光颜色要乘上衰减率
    wold.hit()：世界中的物体是否与光线有交并求出交点信息，有交返回true
    sphere.hit()：球体的求交算法
    material.scatter()：根据入射光、交点信息、衰减率，计算该材质的散射光
*/
int main() {
    // 计时
    auto start = std::chrono::high_resolution_clock::now();

    hittable_list world;

    auto ground_material = make_shared<lambertian>(color(0.5, 0.5, 0.5));
    world.add(make_shared<sphere>(point3(0, -1000, 0), 1000, ground_material));     // 地面

    // x和y的范围
    for (int a = -11; a < 11; a++) {
        for (int b = -11; b < 11; b++) {
            auto choose_mat = random_double();
            point3 center(a + 0.9 * random_double(), 0.2, b + 0.9 * random_double());   // y坐标都是0.2

            if ((center - point3(4, 0.2, 0)).length() > 0.9) {
                shared_ptr<material> sphere_material;

                if (choose_mat < 0.8) {
                    // lambert漫反射
                    auto albedo = color::random() * color::random();
                    sphere_material = make_shared<lambertian>(albedo);
                    world.add(make_shared<sphere>(center, 0.2, sphere_material));
                }
                else if (choose_mat < 0.95) {
                    // metal镜面反射
                    auto albedo = color::random(0.5, 1);
                    auto fuzz = random_double(0, 0.5);
                    sphere_material = make_shared<metal>(albedo, fuzz);
                    world.add(make_shared<sphere>(center, 0.2, sphere_material));
                }
                else {
                    // glass玻璃折射+反射（模糊）
                    sphere_material = make_shared<dielectric>(1.5);
                    world.add(make_shared<sphere>(center, 0.2, sphere_material));
                }
            }
        }
    }

    // 三个半径1的大球，对应三种材质
    auto material1 = make_shared<dielectric>(1.5);
    world.add(make_shared<sphere>(point3(0, 1, 0), 1.0, material1));

    auto material2 = make_shared<lambertian>(color(0.4, 0.2, 0.1));
    world.add(make_shared<sphere>(point3(-4, 1, 0), 1.0, material2));

    auto material3 = make_shared<metal>(color(0.7, 0.6, 0.5), 0.0);
    world.add(make_shared<sphere>(point3(4, 1, 0), 1.0, material3));
    camera cam;

    cam.aspect_ratio = 16.0 / 9.0;
    cam.image_width = 1200;
    cam.samples_per_pixel = 500;
    cam.max_depth = 50;

    cam.vfov = 20;
    cam.lookfrom = point3(13, 2, 3);    // 相机位置
    cam.lookat = point3(0, 0, 0);       // 看向原点
    cam.vup = vec3(0, 1, 0);            // 相机向上方向

    cam.defocus_angle = 0.6;
    cam.focus_dist = 10.0;
    cam.render(world);

    // 计算并输出执行时间
    std::chrono::duration<double> cost = std::chrono::high_resolution_clock::now() - start;
    std::cout << "cost time: " << cost.count() << "s" << std::endl;
}